home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume9 / xterm / part05 < prev    next >
Encoding:
Internet Message Format  |  1987-04-20  |  59.9 KB

  1. Subject:  v09i058:  Terminal emulator for X window system, Part05/07
  2. Newsgroups: mod.sources
  3. Approved: rs@mirror.TMC.COM
  4.  
  5. Submitted by: edmoy%opal.Berkeley.EDU@berkeley.edu
  6. Mod.sources: Volume 9, Issue 58
  7. Archive-name: xterm6.6b/Part05
  8.  
  9. #! /bin/sh
  10. # This is a shell archive, meaning:
  11. # 1. Remove everything above the #! /bin/sh line.
  12. # 2. Save the resulting text in a file.
  13. # 3. Execute the file with /bin/sh (not csh) to create the files:
  14. #    main.c menu.c
  15. if test -f main.c
  16. then
  17.     echo shar: will not overwrite existing file "'main.c'"
  18. else
  19. echo 'x - main.c'
  20. cat << \RAZZLE!DAZZLE > main.c
  21. /*
  22.  *    $Source: /u1/X/xterm/RCS/main.c,v $
  23.  *    $Header: main.c,v 10.101 86/12/01 16:58:10 swick Rel $
  24.  */
  25.  
  26. #include <X/mit-copyright.h>
  27.  
  28. /* Copyright    Massachusetts Institute of Technology    1984, 1985    */
  29.  
  30. /* main.c */
  31.  
  32. #ifndef lint
  33. static char sccs_id[] = "@(#)main.c\tX10/6.6B\t12/28/86";
  34. #endif    lint
  35.  
  36. #include <pwd.h>
  37. #include <sgtty.h>
  38. #include <sys/wait.h>
  39. #include <sys/time.h>
  40. #include <sys/resource.h>
  41. #include <stdio.h>
  42. #include <sys/file.h>
  43. #include <errno.h>
  44. #include <signal.h>
  45. #include <strings.h>
  46. #include <setjmp.h>
  47. #include <utmp.h>
  48. #include <sys/param.h>    /* for NOFILE */
  49. #include <X/Xlib.h>
  50. #include "scrollbar.h"
  51. #include "ptyx.h"
  52. #include "data.h"
  53. #include "error.h"
  54. #include "main.h"
  55.  
  56. int switchfb[] = {0, 2, 1, 3};
  57.  
  58. static int reapchild ();
  59.  
  60. static char *brdr_color;
  61. static char **command_to_exec;
  62. #ifdef TIOCCONS
  63. static int Console;
  64. #endif TIOCCONS
  65. static struct  sgttyb d_sg = {
  66.         0, 0, 0177, CKILL, EVENP|ODDP|ECHO|XTABS|CRMOD
  67. };
  68. static struct  tchars d_tc = {
  69.         CINTR, CQUIT, CSTART,
  70.         CSTOP, CEOF, CBRK,
  71. };
  72. static struct  ltchars d_ltc = {
  73.         CSUSP, CDSUSP, CRPRNT,
  74.         CFLUSH, CWERASE, CLNEXT
  75. };
  76. static int d_disipline = NTTYDISC;
  77. static int d_lmode = LCRTBS|LCRTERA|LCRTKIL|LCTLECH;
  78. static char def_bold_font[] = DEFBOLDFONT;
  79. static char def_font[] = DEFFONT;
  80. static char def_title_font[] = DEFTITLEFONT;
  81. static char def_icon_font[] = DEFICONFONT;
  82. static char display[256];
  83. static char etc_utmp[] = "/etc/utmp";
  84. static char *get_ty;
  85. static char *iconbitmap;
  86. static int inhibit;
  87. static int log_on;
  88. static int login_shell;
  89. static char passedPty[2];    /* name if pty if slave */
  90. static int loginpty;
  91. static char *tekiconbitmap;
  92. static int tslot;
  93. static char *xdef[] = {
  94.     "ActiveIcon",        /* DEF_ACTIVEICON */
  95.     "AllowIconInput",    /* DEF_ALLOWICONINPUT */
  96.     "AutoRaise",        /* DEF_AUTORAISE */
  97.     "Background",        /* DEF_BACKGROUND */
  98.     "BodyFont",        /* DEF_BODYFONT */
  99.     "BoldFont",        /* DEF_BOLDFONT */
  100.     "Border",        /* DEF_BORDER */
  101.     "BorderWidth",        /* DEF_BORDERWIDTH */
  102.     "C132",            /* DEF_C132 */
  103.     "Curses",        /* DEF_CURSES */
  104.     "Cursor",        /* DEF_CURSOR */
  105.     "DeiconifyWarp",    /* DEF_DEICONWARP */
  106.     "Foreground",        /* DEF_FOREGROUND */
  107.     "IconBitmap",        /* DEF_ICONBITMAP */
  108.     "IconFont",        /* DEF_ICONFONT */
  109.     "IconStartup",        /* DEF_ICONSTARTUP */
  110.     "InternalBorder",    /* DEF_INTERNALBORDER */
  111.     "JumpScroll",        /* DEF_JUMPSCROLL */
  112. #ifdef KEYBD
  113.     "KeyBoard",        /* DEF_KEYBOARD */
  114. #endif KEYBD
  115.     "LogFile",        /* DEF_LOGFILE */
  116.     "Logging",        /* DEF_LOGGING */
  117.     "LogInhibit",        /* DEF_LOGINHIBIT */
  118.     "LoginShell",        /* DEF_LOGINSHELL */
  119.     "MarginBell",        /* DEF_MARGINBELL */
  120.     "Mouse",        /* DEF_MOUSE */
  121.     "NMarginBell",        /* DEF_NMARGINBELL */
  122.     "PageOverlap",        /* DEF_PAGEOVERLAP */
  123.     "PageScroll",        /* DEF_PAGESCROLL */
  124.     "ReverseVideo",        /* DEF_REVERSEVIDEO */
  125.     "ReverseWrap",        /* DEF_REVERSEWRAP */
  126.     "SaveLines",        /* DEF_SAVELINES */
  127.     "ScrollBar",        /* DEF_SCROLLBAR */
  128.     "ScrollInput",        /* DEF_SCROLLINPUT */
  129.     "ScrollKey",        /* DEF_SCROLLKEY */
  130.     "SignalInhibit",    /* DEF_SIGNALINHIBIT */
  131.     "StatusLine",        /* DEF_STATUSLINE */
  132.     "StatusNormal",        /* DEF_STATUSNORMAL */
  133.     "TekIconBitmap",    /* DEF_TEKICONBITMAP */
  134.     "TekInhibit",        /* DEF_TEKINHIBIT */
  135.     "TextUnderIcon",    /* DEF_TEXTUNDERICON */
  136.     "TitleBar",        /* DEF_TITLEBAR */
  137.     "TitleFont",        /* DEF_TITLEFONT */
  138.     "VisualBell",        /* DEF_VISUALBELL */
  139.     0,
  140. };
  141. #ifdef UTMP
  142. static int added_utmp_entry;
  143. #endif UTMP
  144.  
  145. main (argc, argv)
  146. int argc;
  147. char **argv;
  148. {
  149.     register Screen *screen = &term.screen;
  150.     register char *strind;
  151.     register int i, pty;
  152.     register char **cp;
  153.     short fnflag = 0;    /* True iff -fn option used */
  154.     short fbflag = 0;    /* True iff -fb option used */
  155.     int Xsocket, mode;
  156.     extern onalarm();
  157.     char *malloc();
  158.     char *basename();
  159.     int xerror(), xioerror();
  160. #ifdef KEYBD
  161.     extern char *keyboardtype;    /* used in XKeyBind.c */
  162.     char *getenv();
  163. #endif KEYBD
  164.  
  165.     xterm_name = (strcmp(*argv, "-") == 0) ? "xterm" : basename(*argv);
  166.  
  167.     term.flags = WRAPAROUND | SMOOTHSCROLL | AUTOREPEAT;
  168.     screen->border = DEFBORDER;
  169.     screen->borderwidth = DEFBORDERWIDTH;
  170.     screen->reversestatus = TRUE;
  171.     screen->mappedVwin = &screen->fullVwin;
  172.     screen->mappedTwin = &screen->fullTwin;
  173.     f_b = def_bold_font;
  174.     f_n = def_font;
  175.     f_t = def_title_font;
  176.     f_i = def_icon_font;
  177.  
  178.     display[0] = '\0';
  179. #ifdef KEYBD
  180.     if((strind = getenv("KEYBD")) && *strind) {
  181.         if((keyboardtype = malloc(strlen(strind) + 1)) == NULL)
  182.             SysError(ERROR_KMALLOC);
  183.         strcpy(keyboardtype, strind);
  184.     }
  185. #endif KEYBD
  186.  
  187.     /*
  188.      * go get options out of default file
  189.      */
  190.     for(i = 0, cp = xdef ; *cp ; i++, cp++) {
  191.         if(!(strind = XGetDefault(xterm_name, *cp)))
  192.             continue;
  193.         switch(i) {
  194.          case DEF_ACTIVEICON:
  195.             if (strcmp (strind, "on") == 0)
  196.                 screen->active_icon = TRUE;
  197.             continue;
  198.          case DEF_ALLOWICONINPUT:
  199.              if (strcmp (strind, "on") == 0)
  200.                     term.flags |= ICONINPUT;
  201.             continue;
  202.          case DEF_AUTORAISE:
  203.             if (strcmp (strind, "on") == 0) 
  204.                 screen->autoraise = TRUE;
  205.             continue;
  206.          case DEF_BACKGROUND:
  207.             back_color = strind;
  208.             continue;
  209.          case DEF_BODYFONT:
  210.             f_n = strind;
  211.             fnflag = TRUE;
  212.             continue;
  213.          case DEF_BOLDFONT:
  214.             f_b = strind;
  215.             fbflag = TRUE;
  216.             continue;
  217.          case DEF_BORDER:
  218.             brdr_color = strind;
  219.             continue;
  220.          case DEF_BORDERWIDTH:
  221.             screen->borderwidth = atoi (strind);
  222.             continue;
  223.          case DEF_C132:
  224.             if (strcmp (strind, "on") == 0) 
  225.                 screen->c132 = TRUE;
  226.             continue;
  227.          case DEF_CURSES:
  228.             if (strcmp (strind, "on") == 0) 
  229.                 screen->curses = TRUE;
  230.             continue;
  231.          case DEF_CURSOR:
  232.             curs_color = strind;
  233.             continue;
  234.          case DEF_DEICONWARP:
  235.             if (strcmp (strind, "on") == 0)
  236.                 screen->deiconwarp = TRUE;
  237.             continue;
  238.          case DEF_FOREGROUND:
  239.             fore_color = strind;
  240.             continue;
  241.          case DEF_ICONBITMAP:
  242.             iconbitmap = strind;
  243.             continue;
  244.          case DEF_ICONFONT:
  245.              f_i = strind;
  246.             continue;
  247.          case DEF_ICONSTARTUP:
  248.             if (strcmp (strind, "on") == 0)
  249.                 screen->icon_show = -1;
  250.             continue;
  251.          case DEF_INTERNALBORDER:
  252.             screen->border = atoi (strind);
  253.             continue;
  254.          case DEF_JUMPSCROLL:
  255.             if (strcmp (strind, "on") == 0) {
  256.                 screen->jumpscroll = TRUE;
  257.                 term.flags &= ~SMOOTHSCROLL;
  258.             }
  259.             continue;
  260. #ifdef KEYBD
  261.          case DEF_KEYBOARD:
  262.             if(keyboardtype)
  263.                 free(keyboardtype);
  264.             keyboardtype = strind;
  265.             continue;
  266. #endif KEYBD
  267.          case DEF_LOGFILE:
  268.             if(screen->logfile = malloc(strlen(strind) + 1))
  269.                 strcpy(screen->logfile, strind);
  270.             continue;
  271.          case DEF_LOGGING:
  272.             if (strcmp (strind, "on") == 0) 
  273.                 log_on = TRUE;
  274.             continue;
  275.          case DEF_LOGINHIBIT:
  276.             if (strcmp (strind, "on") == 0) 
  277.                 inhibit |= I_LOG;
  278.             continue;
  279.          case DEF_LOGINSHELL:
  280.             if (strcmp (strind, "on") == 0) 
  281.                 login_shell = TRUE;
  282.             continue;
  283.          case DEF_MARGINBELL:
  284.             if (strcmp (strind, "on") == 0) 
  285.                 screen->marginbell = TRUE;
  286.             continue;
  287.          case DEF_MOUSE:
  288.             mous_color = strind;
  289.             continue;
  290.          case DEF_NMARGINBELL:
  291.             n_marginbell = atoi (strind);
  292.             continue;
  293.          case DEF_PAGEOVERLAP:
  294.             if((screen->pageoverlap = atoi (strind) - 1) < 0)
  295.                 screen->pageoverlap = -1;
  296.             continue;
  297.          case DEF_PAGESCROLL:
  298.             if (strcmp (strind, "on") == 0)
  299.                 screen->pagemode = TRUE;
  300.             continue;
  301.          case DEF_REVERSEVIDEO:
  302.             if (strcmp (strind, "on") == 0)
  303.                 re_verse = TRUE;
  304.             continue;
  305.          case DEF_REVERSEWRAP:
  306.             if (strcmp (strind, "on") == 0) 
  307.                 term.flags |= REVERSEWRAP;
  308.             continue;
  309.          case DEF_SAVELINES:
  310.             save_lines = atoi (strind);
  311.             continue;
  312.          case DEF_SCROLLBAR:
  313.             if (strcmp (strind, "on") == 0) 
  314.                 screen->scrollbar = SCROLLBARWIDTH;
  315.             continue;
  316.          case DEF_SCROLLINPUT:
  317.             if (strcmp (strind, "on") == 0) 
  318.                 screen->scrollinput = TRUE;
  319.             continue;
  320.          case DEF_SCROLLKEY:
  321.             if (strcmp (strind, "on") == 0) 
  322.                 screen->scrollkey = TRUE;
  323.             continue;
  324.          case DEF_SIGNALINHIBIT:
  325.             if (strcmp (strind, "on") == 0) 
  326.                 inhibit |= I_SIGNAL;
  327.             continue;
  328.          case DEF_STATUSLINE:
  329.             if (strcmp (strind, "on") == 0) 
  330.                 screen->statusline = TRUE;
  331.             continue;
  332.          case DEF_STATUSNORMAL:
  333.             screen->reversestatus = (strcmp (strind, "on") != 0);
  334.             continue;
  335.          case DEF_TEKICONBITMAP:
  336.             tekiconbitmap = strind;
  337.             continue;
  338.          case DEF_TEKINHIBIT:
  339.             if (strcmp (strind, "on") == 0) 
  340.                 inhibit |= I_TEK;
  341.             continue;
  342.          case DEF_TEXTUNDERICON:
  343.             if (strcmp (strind, "on") == 0) 
  344.                 screen->textundericon = TRUE;
  345.             continue;
  346.          case DEF_TITLEBAR:
  347.             if (strcmp (strind, "on") == 0) 
  348.                 screen->fullVwin.titlebar = TRUE;
  349.             continue;
  350.          case DEF_TITLEFONT:
  351.             f_t = strind;
  352.             continue;
  353.          case DEF_VISUALBELL:
  354.             if (strcmp (strind, "on") == 0) 
  355.                 screen->visualbell = TRUE;
  356.             continue;
  357.         }
  358.     }
  359.  
  360.     /* parse command line */
  361.     
  362.     for (argc--, argv++ ; argc > 0 ; argc--, argv++) {
  363.         if (**argv == '=') {
  364.         geo_metry = *argv;
  365.         continue;
  366.         }
  367.  
  368.         if (**argv == '%') {
  369.         T_geometry = *argv;
  370.         *T_geometry = '=';
  371.         continue;
  372.         }
  373.  
  374.         if (**argv == '#') {
  375.         icon_geom = *argv;
  376.         *icon_geom = '=';
  377.         continue;
  378.         }
  379.  
  380.         if((strind = index (*argv, ':')) != NULL) {
  381.         strncpy(display, *argv, sizeof(display));
  382.         continue;
  383.         }
  384.  
  385.         if(!(i = (**argv == '-')) && **argv != '+') Syntax ();
  386.  
  387.         switch(argument(&(*argv)[1])) {
  388.          case ARG_132:
  389.         screen->c132 = i;
  390.         continue;
  391. #ifdef TIOCCONS
  392.          case ARG__C:
  393.         Console = i;
  394.         continue;
  395. #endif TIOCCONS
  396.          case ARG__L:
  397.         {
  398.         char tt[32];
  399.  
  400.         L_flag = 1;
  401.         get_ty = argv[--argc];
  402.         strcpy(tt,"/dev/");
  403.         strcat(tt, get_ty);
  404.         tt[5] = 'p';
  405.         loginpty = open( tt, O_RDWR, 0 );
  406.         dup2( loginpty, 4 );
  407.         close( loginpty );
  408.         loginpty = 4;
  409.         tt[5] = 't';
  410.         chown(tt, 0, 0);
  411.         chmod(tt, 0622);
  412.         if (open(tt, O_RDWR) < 0) {
  413.             consolepr("open failed\n");
  414.         }
  415.         signal(SIGHUP, SIG_IGN);
  416.         vhangup();
  417.         setpgrp(0,0);
  418.         signal(SIGHUP, SIG_DFL);
  419.         (void) close(0);
  420.         open(tt, O_RDWR, 0);
  421.         dup2(0, 1);
  422.         dup2(0, 2);
  423.         continue;
  424.         }
  425.          case ARG__S:
  426.         if(i) {
  427.             if (--argc <= 0) Syntax ();
  428.             sscanf(*++argv, "%c%c%d", passedPty, passedPty+1,
  429.              &am_slave);
  430.             if (am_slave <= 0) Syntax();
  431.         } else
  432.             am_slave = 0;
  433.         continue;
  434.          case ARG_AI:
  435.             screen->active_icon = i;
  436.         continue;
  437.          case ARG_AR:
  438.         screen->autoraise = i;
  439.         continue;
  440.          case ARG_B:
  441.         if(i) {
  442.             if (--argc <= 0) Syntax ();
  443.             screen->border = atoi (*++argv);
  444.         } else
  445.             screen->border = DEFBORDER;
  446.         continue;
  447.          case ARG_BD:
  448.         if(i) {
  449.             if (--argc <= 0) Syntax ();
  450.             brdr_color = *++argv;
  451.         } else
  452.             brdr_color = NULL;
  453.         continue;
  454.          case ARG_BG:
  455.         if(i) {
  456.             if (--argc <= 0) Syntax ();
  457.             back_color = *++argv;
  458.         } else
  459.             back_color = NULL;
  460.         continue;
  461.          case ARG_BW:
  462.         if(i) {
  463.             if (--argc <= 0) Syntax ();
  464.             screen->borderwidth = atoi (*++argv);
  465.         } else
  466.             screen->borderwidth = DEFBORDERWIDTH;
  467.         continue;
  468.          case ARG_CR:
  469.         if(i) {
  470.             if (--argc <= 0) Syntax ();
  471.             curs_color = *++argv;
  472.         } else
  473.             curs_color = NULL;
  474.         continue;
  475.          case ARG_CU:
  476.         screen->curses = i;
  477.         continue;
  478. #ifdef DEBUG
  479.          case ARG_D:
  480.         debug = i;
  481.         continue;
  482. #endif DEBUG
  483.          case ARG_DW:
  484.         screen->deiconwarp = i;
  485.         continue;
  486.          case ARG_E:
  487.          if(!i) Syntax();
  488.         if (argc <= 1) Syntax ();
  489.         command_to_exec = ++argv;
  490.         break;
  491.          case ARG_FB:
  492.         if(fbflag = i) {
  493.             if (--argc <= 0) Syntax ();
  494.             f_b = *++argv;
  495.             fbflag = TRUE;
  496.         } else {
  497.             f_b = def_bold_font;
  498.             fbflag = FALSE;
  499.         }
  500.         continue;
  501.          case ARG_FG:
  502.         if(i) {
  503.             if (--argc <= 0) Syntax ();
  504.             fore_color = *++argv;
  505.         } else
  506.             fore_color = NULL;
  507.         continue;
  508.          case ARG_FI:
  509.             if (i) {
  510.             if (--argc <= 0) Syntax();
  511.             f_i = *++argv;
  512.         } else
  513.             f_i = def_icon_font;
  514.         continue;
  515.          case ARG_FN:
  516.         if(fnflag = i) {
  517.             if (--argc <= 0) Syntax ();
  518.             f_n = *++argv;
  519.             fnflag = TRUE;
  520.         } else {
  521.             f_n = def_font;
  522.             fnflag = FALSE;
  523.         }
  524.         continue;
  525.          case ARG_FT:
  526.         if(i) {
  527.             if (--argc <= 0) Syntax ();
  528.             f_t = *++argv;
  529.         } else
  530.             f_t = def_title_font;
  531.         continue;
  532.          case ARG_I:
  533.         screen->icon_show = i ? -1 : 0;
  534.         continue;
  535.          case ARG_IB:
  536.         if(i) {
  537.             if (--argc <= 0) Syntax ();
  538.             iconbitmap = *++argv;
  539.         } else
  540.             iconbitmap = NULL;
  541.         continue;
  542.          case ARG_IT:
  543.         if(i) {
  544.             if (--argc <= 0) Syntax ();
  545.             tekiconbitmap = *++argv;
  546.         } else
  547.             tekiconbitmap = NULL;
  548.         continue;
  549.          case ARG_J:
  550.         if(screen->jumpscroll = i)
  551.             term.flags &= ~SMOOTHSCROLL;
  552.         else
  553.             term.flags |= SMOOTHSCROLL;
  554.         continue;
  555. #ifdef KEYBD
  556.          case ARG_K:
  557.         if(i) {
  558.             if (--argc <= 0) Syntax ();
  559.             keyboardtype = *++argv;
  560.         } else
  561.             keyboardtype = NULL;
  562.         continue;
  563. #endif KEYBD
  564.          case ARG_L:
  565.         log_on = i;
  566.         continue;
  567.          case ARG_LF:
  568.         if(screen->logfile)
  569.             free(screen->logfile);
  570.         if(i) {
  571.             if (--argc <= 0) Syntax ();
  572.             if(screen->logfile = malloc(strlen(*++argv) + 1))
  573.                 strcpy(screen->logfile, *argv);
  574.         } else
  575.             screen->logfile = NULL;
  576.         continue;
  577.          case ARG_LS:
  578.         login_shell = i;
  579.         continue;
  580.          case ARG_MB:
  581.         screen->marginbell = i;
  582.         continue;
  583.          case ARG_MS:
  584.         if(i) {
  585.             if (--argc <= 0) Syntax ();
  586.             mous_color = *++argv;
  587.         } else
  588.             mous_color = NULL;
  589.         continue;
  590.          case ARG_N:
  591.         if(i) {
  592.             if (--argc <= 0) Syntax ();
  593.             win_name = *++argv;
  594.         } else
  595.             win_name = NULL;
  596.         continue;
  597.          case ARG_NB:
  598.         if(i) {
  599.             if (--argc <= 0) Syntax ();
  600.             n_marginbell = atoi (*++argv);
  601.         } else
  602.             n_marginbell = N_MARGINBELL;
  603.         continue;
  604.          case ARG_PO:
  605.         if(i) {
  606.             if (--argc <= 0) Syntax ();
  607.             if((screen->pageoverlap = atoi (*++argv) - 1) < 0)
  608.             screen->pageoverlap = -1;
  609.         } else
  610.             screen->pageoverlap = 0;
  611.         continue;
  612.          case ARG_PS:
  613.         screen->pagemode = i;
  614.         continue;
  615.          case ARG_RV:
  616.         re_verse = i;
  617.         continue;
  618.          case ARG_RW:
  619.         if(i)
  620.             term.flags |= REVERSEWRAP;
  621.         else
  622.             term.flags &= ~REVERSEWRAP;
  623.         continue;
  624.          case ARG_S:
  625.         screen->multiscroll = i;
  626.         continue;
  627.          case ARG_SB:
  628.         screen->scrollbar = i ? SCROLLBARWIDTH : 0;
  629.         continue;
  630.          case ARG_SI:
  631.         screen->scrollinput = i;
  632.         continue;
  633.          case ARG_SK:
  634.         screen->scrollkey = i;
  635.         continue;
  636.          case ARG_SL:
  637.         if(i) {
  638.             if (--argc <= 0) Syntax ();
  639.             save_lines = atoi (*++argv);
  640.         } else
  641.             save_lines = SAVELINES;
  642.         continue;
  643.          case ARG_SN:
  644.         screen->reversestatus = !i;
  645.         continue;
  646.          case ARG_ST:
  647.         screen->statusline = i;
  648.         continue;
  649.          case ARG_T:
  650.         screen->TekEmu = i;
  651.         continue;
  652.          case ARG_TB:
  653.         screen->fullVwin.titlebar = i;
  654.         continue;
  655.          case ARG_TI:
  656.         screen->textundericon = i;
  657.         continue;
  658.          case ARG_VB:
  659.         screen->visualbell = i;
  660.         continue;
  661.          default:
  662.         Syntax ();
  663.         }
  664.         break;
  665.     }
  666.  
  667.     term.initflags = term.flags;
  668.  
  669.     if (fnflag && !fbflag) f_b = NULL;
  670.     if (!fnflag && fbflag) f_n = f_b;
  671.     if(!win_name) {
  672.         if(get_ty) {
  673.             char b[256];
  674.  
  675.             gethostname(b, sizeof(b) - 1);
  676.             b[sizeof(b) - 1] = 0;
  677.             if(strind = index(b, '.')) /* remove domain */
  678.                 *strind = 0;
  679.             win_name = malloc(strlen(b) + 8);
  680.             strcpy(win_name, "login(");
  681.             strcat(win_name, b);
  682.             strcat(win_name, ")");
  683.         } else
  684.             win_name = (am_slave ? "xterm slave" :
  685.              (command_to_exec ? basename(command_to_exec[0]) :
  686.              xterm_name));
  687.     }
  688.     if(inhibit & I_TEK)
  689.         screen->TekEmu = FALSE;
  690.  
  691.     /* set up stderr properly */
  692.     i = -1;
  693. #ifdef DEBUG
  694.     if(debug)
  695.         i = open ("xterm.debug.log", O_WRONLY | O_CREAT | O_TRUNC,
  696.          0666);
  697.     else
  698. #endif DEBUG
  699.     if(get_ty)
  700.         i = open("/dev/console", O_WRONLY);
  701.     if(i >= 0)
  702.         fileno(stderr) = i;
  703.     if(fileno(stderr) != (NOFILE - 1)) {
  704.         dup2(fileno(stderr), (NOFILE - 1));
  705.         if(fileno(stderr) >= 3)
  706.             close(fileno(stderr));
  707.         fileno(stderr) = (NOFILE - 1);
  708.     }
  709.  
  710.     signal (SIGCHLD, reapchild);
  711.     signal (SIGHUP, SIG_IGN);
  712.     signal(SIGALRM, onalarm);
  713.  
  714.     /* open a terminal for client */
  715.     get_terminal ();
  716.     spawn ();
  717.  
  718.     Xsocket = screen->display->fd;
  719.     pty = screen->respond;
  720.  
  721.     if (am_slave) { /* Write window id so master end can read and use */
  722.         write(pty, screen->TekEmu ? (char *)&TWindow(screen) :
  723.          (char *)&VWindow(screen), sizeof(Window));
  724.         write(pty, "\n", 1);
  725.     }
  726.  
  727.     if(log_on) {
  728.         log_on = FALSE;
  729.         StartLog(screen);
  730.     }
  731.     screen->inhibit = inhibit;
  732.     mode = 1;
  733.     if (ioctl (pty, FIONBIO, &mode) == -1) SysError (ERROR_FIONBIO);
  734.     
  735.     pty_mask = 1 << pty;
  736.     X_mask = 1 << Xsocket;
  737.     Select_mask = pty_mask | X_mask;
  738.     max_plus1 = (pty < Xsocket) ? (1 + Xsocket) : (1 + pty);
  739.  
  740. #ifdef DEBUG
  741.     if (debug) printf ("debugging on\n");
  742. #endif DEBUG
  743.     XErrorHandler(xerror);
  744.     XIOErrorHandler(xioerror);
  745.     for( ; ; )
  746.         if(screen->TekEmu)
  747.             TekRun();
  748.         else
  749.             VTRun();
  750. }
  751.  
  752. char *basename(name)
  753. char *name;
  754. {
  755.     register char *cp;
  756.     char *rindex();
  757.  
  758.     return((cp = rindex(name, '/')) ? cp + 1 : name);
  759. }
  760.  
  761. static struct argstr {
  762.     char *arg;
  763.     int val;
  764. } arg[] = {
  765.     {"132",    ARG_132},
  766. #ifdef TIOCCONS
  767.     {"C",    ARG__C},
  768. #endif TIOCCONS
  769.     {"L",    ARG__L},
  770.     {"S",    ARG__S},
  771.     {"ai",    ARG_AI},
  772.     {"ar",    ARG_AR},
  773.     {"b",    ARG_B},
  774.     {"bd",    ARG_BD},
  775.     {"bg",    ARG_BG},
  776.     {"bw",    ARG_BW},
  777.     {"cr",    ARG_CR},
  778.     {"cu",    ARG_CU},
  779. #ifdef DEBUG
  780.     {"d",    ARG_D},
  781. #endif DEBUG
  782.     {"dw",    ARG_DW},
  783.     {"e",    ARG_E},
  784.     {"fb",    ARG_FB},
  785.     {"fg",    ARG_FG},
  786.     {"fi",    ARG_FI},
  787.     {"fn",    ARG_FN},
  788.     {"ft",    ARG_FT},
  789.     {"i",    ARG_I},
  790.     {"ib",    ARG_IB},
  791.     {"it",    ARG_IT},
  792.     {"j",    ARG_J},
  793. #ifdef KEYBD
  794.     {"k",    ARG_K},
  795. #endif KEYBD
  796.     {"l",    ARG_L},
  797.     {"lf",    ARG_LF},
  798.     {"ls",    ARG_LS},
  799.     {"mb",    ARG_MB},
  800.     {"ms",    ARG_MS},
  801.     {"n",    ARG_N},
  802.     {"nb",    ARG_NB},
  803.     {"po",    ARG_PO},
  804.     {"ps",    ARG_PS},
  805.     {"r",    ARG_RV},
  806.     {"rv",    ARG_RV},
  807.     {"rw",    ARG_RW},
  808.     {"s",    ARG_S},
  809.     {"sb",    ARG_SB},
  810.     {"si",    ARG_SI},
  811.     {"sk",    ARG_SK},
  812.     {"sl",    ARG_SL},
  813.     {"sn",    ARG_SN},
  814.     {"st",    ARG_ST},
  815.     {"t",    ARG_T},
  816.     {"tb",    ARG_TB},
  817.     {"ti",    ARG_TI},
  818.     {"vb",    ARG_VB},
  819.     {"w",    ARG_BW},
  820. };
  821.  
  822. argument(s)
  823. register char *s;
  824. {
  825.     register int i, low, high, com;
  826.  
  827.     low = 0;
  828.     high = sizeof(arg) / sizeof(struct argstr) - 1;
  829.     while(low <= high) {/* use binary search, arg in lexigraphic order */
  830.         i = (low + high) / 2;
  831.         if ((com = strcmp(s, arg[i].arg)) == 0)
  832.             return(arg[i].val);
  833.         if(com > 0)
  834.             low = i + 1;
  835.         else
  836.             high = i - 1;
  837.     }
  838.     return(-1);
  839. }
  840.  
  841. static char *ustring[] = {
  842. "Usage: xterm [-132] [-ai] [-ar] [-b margin_width] [-bd border_color] \\\n",
  843. #ifdef ARG__C
  844. " [-bg backgrnd_color] [-bw border_width] [-C] [-cr cursor_color] [-cu] \\\n",
  845. #else ARG__C
  846. " [-bg backgrnd_color] [-bw border_width] [-cr cursor_color] [-cu] \\\n",
  847. #endif ARG__C
  848. " [-dw] [-fb bold_font] [-fg foregrnd_color] [-fi icon_font] [-fn norm_font] \\\n",
  849. " [-ft title_font] [-i] [-ib iconbitmap] [-it tekiconbitmap] [-j] \\\n",
  850. #ifdef ARG_K
  851. " [-k keybd] [-l] [-lf logfile] [-ls] [-mb] [-ms mouse_color] \\\n",
  852. #else ARG_K
  853. " [-l] [-lf logfile] [-ls] [-mb] [-ms mouse_color] \\\n",
  854. #endif ARG_K
  855. " [-n name] [-nb bell_margin] [-po] [-ps] [-rv] [-rw] [-s] \\\n",
  856. " [-sb] [-si] [-sk] [-sl save_lines] [-sn] [-st] [-t] [-tb] \\\n",
  857. " [-ti] [-vb] [=[width]x[height][[+-]xoff[[+-]yoff]]] \\\n",
  858. " [%[width]x[height][[+-]xoff[[+-]yoff]]] [#[+-]xoff[[+-]yoff]] \\\n",
  859. " [-e command_to_exec]\n\n",
  860. "Fonts must be of fixed width and of same size;\n",
  861. "If only one font is specified, it will be used for normal and bold text\n",
  862. "The -132 option allows 80 <-> 132 column escape sequences\n",
  863. "The -ai option turns on miniature (active) icons\n",
  864. "The -ar option turns auto raise window mode on\n",
  865. #ifdef ARG__C
  866. "The -C option forces output to /dev/console to appear in this window\n",
  867. #endif ARG__C
  868. "The -cu option turns a curses bug fix on\n",
  869. "The -dw option warps the mouse on deiconify\n",
  870. "The -i option enables icon startup\n",
  871. "The -j option enables jump scroll\n",
  872. "The -l option enables logging\n",
  873. "The -ls option makes the shell a login shell\n",
  874. "The -mb option turns the margin bell on\n",
  875. "The -ps option turns page scroll on\n",
  876. "The -rv option turns reverse video on\n",
  877. "The -rw option turns reverse wraparound on\n",
  878. "The -s option enables asynchronous scrolling\n",
  879. "The -sb option enables the scrollbar\n",
  880. "The -si option enables re-positioning the scrollbar at the bottom on input\n",
  881. "The -sk option causes the scrollbar to position at the bottom on a key\n",
  882. "The -sn option makes the status line normal video \n",
  883. "The -st option enables the status line\n",
  884. "The -t option starts Tektronix mode\n",
  885. "The -tb option enables the titlebar\n",
  886. "The -ti option places the window name under the icon\n",
  887. "The -vb option enables visual bell\n",
  888. 0
  889. };
  890.  
  891. Syntax ()
  892. {
  893.     register char **us = ustring;
  894.  
  895.     while (*us) fputs(*us++, stderr);
  896.     exit (1);
  897. }
  898.  
  899. get_pty (pty, tty)
  900. /*
  901.    opens a pty, storing fildes in pty and tty.
  902.  */
  903. int *pty, *tty;
  904. {
  905.     int devindex, letter = 0;
  906.  
  907.     while (letter < 4) {
  908.         ttydev [8] = ptydev [8] = "pqrs" [letter++];
  909.         devindex = 0;
  910.  
  911.         while (devindex < 16) {
  912.         ttydev [9] = ptydev [9] = "0123456789abcdef" [devindex++];
  913.         if ((*pty = open (ptydev, O_RDWR)) < 0)
  914.             continue;
  915.         if ((*tty = open (ttydev, O_RDWR)) < 0) {
  916.             close(*pty);
  917.             continue;
  918.         }
  919.         return;
  920.         }
  921.     }
  922.     
  923.     fprintf (stderr, "%s: Not enough available pty's\n", xterm_name);
  924.     exit (ERROR_PTYS);
  925. }
  926.  
  927. get_terminal ()
  928. /* 
  929.  * sets up X and initializes the terminal structure except for term.buf.fildes.
  930.  */
  931. {
  932.     register Screen *screen = &term.screen;
  933.     register int try;
  934.     Color cdef;
  935.     char *malloc();
  936.     
  937.     for (try = 10 ; ; ) {
  938.         if (screen->display = XOpenDisplay(display))
  939.         break;
  940.         if (!get_ty) {
  941.         fprintf(stderr, "%s: No such display server %s\n", xterm_name,
  942.          XDisplayName(display));
  943.         exit(ERROR_NOX);
  944.         }
  945.         if (--try <= 0)  {
  946.         fprintf (stderr, "%s: Can't connect to display server %s\n",
  947.          xterm_name, XDisplayName(display));
  948.         exit (ERROR_NOX2);
  949.         }        
  950.         sleep (5);
  951.     }
  952.  
  953.     if(re_verse) {
  954.         B_Pixel = WhitePixel;
  955.         B_Pixmap = WhitePixmap;
  956.         W_Pixel = BlackPixel;
  957.         W_Pixmap = BlackPixmap;
  958.     } else {
  959.         B_Pixel = BlackPixel;
  960.         B_Pixmap = BlackPixmap;
  961.         W_Pixel = WhitePixel;
  962.         W_Pixmap = WhitePixmap;
  963.     }
  964.  
  965.     if (brdr_color && DisplayCells() > 2 &&
  966.      XParseColor(brdr_color, &cdef) && XGetHardwareColor(&cdef)) {
  967.         if(!(screen->bordertile = XMakeTile(cdef.pixel)))
  968.         Error(ERROR_BORDER);
  969.     } else
  970.         screen->bordertile = B_Pixmap;
  971.     screen->graybordertile = make_gray();
  972.  
  973.     screen->foreground = B_Pixel;
  974.     screen->background = W_Pixel;
  975.     screen->cursorcolor = B_Pixel;
  976.     screen->mousecolor = B_Pixel;
  977.  
  978.     if (DisplayCells() > 2 && (fore_color || back_color ||
  979.      curs_color)) {
  980.         if (fore_color && XParseColor(fore_color, &cdef) &&
  981.          XGetHardwareColor(&cdef)) {
  982.             screen->foreground = cdef.pixel;
  983.             screen->color |= C_FOREGROUND;
  984.         }
  985.         if (back_color && XParseColor(back_color, &cdef) &&
  986.          XGetHardwareColor(&cdef)) {
  987.             screen->background = cdef.pixel;
  988.             screen->color |= C_BACKGROUND;
  989.         }
  990.         if (curs_color && XParseColor(curs_color, &cdef) &&
  991.          XGetHardwareColor(&cdef)) {
  992.             screen->cursorcolor = cdef.pixel;
  993.             screen->color |= C_CURSOR;
  994.         } else
  995.             screen->cursorcolor = screen->foreground;
  996.     }
  997.  
  998.     if (mous_color && DisplayCells() > 2 &&
  999.      XParseColor(mous_color, &cdef) && XGetHardwareColor(&cdef)) {
  1000.         screen->mousecolor = cdef.pixel;
  1001.         screen->color |= C_MOUSE;
  1002.     } else
  1003.         screen->mousecolor = screen->cursorcolor;
  1004.  
  1005.     if(screen->color & C_BACKGROUND) {
  1006.         if(!(screen->bgndtile = XMakeTile(screen->background)))
  1007.         Error(ERROR_BACK);
  1008.     } else
  1009.         screen->bgndtile = W_Pixmap;
  1010.     screen->arrow = make_arrow(screen->mousecolor, screen->background,
  1011.      GXcopy);
  1012.  
  1013.     XAutoRepeatOn();
  1014.     if((screen->titlefont = XOpenFont(f_t)) == NULL) {
  1015.         fprintf(stderr, "%s: Can't get title font %s\n", xterm_name,
  1016.          f_t);
  1017.         exit(ERROR_TITLEFONT);
  1018.     }
  1019.     screen->title_n_size= XQueryWidth("m", screen->titlefont->id);
  1020.     screen->titleheight = screen->titlefont->height + 2 * TITLEPAD + 1;
  1021.     if(screen->fullVwin.titlebar)
  1022.         screen->fullVwin.titlebar =
  1023.             screen->fullTwin.titlebar = screen->titleheight;
  1024.     IconInit(screen, iconbitmap, tekiconbitmap);
  1025. }
  1026.  
  1027. static char *tekterm[] = {
  1028.     "tek4015",
  1029.     "tek4014",
  1030.     "tek4013",
  1031.     "tek4010",
  1032.     "dumb",
  1033.     0
  1034. };
  1035.  
  1036. static char *vtterm[] = {
  1037.     "xterms",
  1038.     "xterm",
  1039.     "vt102",
  1040.     "vt100",
  1041.     "ansi",
  1042.     "dumb",
  1043.     0
  1044. };
  1045.  
  1046. spawn ()
  1047. /* 
  1048.  *  Inits pty and tty and forks a login process.
  1049.  *  Does not close fd Xsocket.
  1050.  *  If getty,  execs getty rather than csh and uses std fd's rather
  1051.  *  than opening a pty/tty pair.
  1052.  *  If slave, the pty named in passedPty is already open for use
  1053.  */
  1054. {
  1055.     register Screen *screen = &term.screen;
  1056.     int Xsocket = screen->display->fd;
  1057.     int index1, tty = -1;
  1058.     int discipline;
  1059.     unsigned lmode;
  1060.     struct tchars tc;
  1061.     struct ltchars ltc;
  1062.     struct sgttyb sg;
  1063.  
  1064.     char termcap [1024];
  1065.     char newtc [1024];
  1066.     char *ptr, *shname;
  1067.     int i, no_dev_tty = FALSE;
  1068.     char **envnew;        /* new environment */
  1069.     char buf[32];
  1070.     char *TermName = NULL;
  1071.     int ldisc = 0;
  1072. #ifdef sun
  1073. #ifdef TIOCSSIZE
  1074.     struct ttysize ts;
  1075. #endif TIOCSSIZE
  1076. #else sun
  1077. #ifdef TIOCSWINSZ
  1078.     struct winsize ws;
  1079. #endif TIOCSWINSZ
  1080. #endif sun
  1081.     struct passwd *pw = NULL;
  1082. #ifdef UTMP
  1083.     struct utmp utmp;
  1084. #endif UTMP
  1085.     extern int Exit();
  1086.     struct passwd *getpwuid();
  1087.     char *getenv();
  1088.     char *index (), *rindex (), *strindex ();
  1089.  
  1090.     screen->uid = getuid();
  1091.     screen->gid = getgid();
  1092.  
  1093. #ifdef UTMP
  1094.     added_utmp_entry = FALSE;
  1095. #endif UTMP
  1096.     /* so that TIOCSWINSZ || TIOCSIZE doesn't block */
  1097.     signal(SIGTTOU,SIG_IGN);
  1098.     if(!(screen->TekEmu ? TekInit() : VTInit()))
  1099.         exit(ERROR_INIT);
  1100.  
  1101.     if(screen->TekEmu) {
  1102.         envnew = tekterm;
  1103.         ptr = newtc;
  1104.     } else {
  1105.         /*
  1106.          * Special case of a 80x24 window, use "xterms"
  1107.          */
  1108.         envnew = (screen->max_col == 79 && screen->max_row ==
  1109.          23) ? vtterm : &vtterm[1];
  1110.         ptr = termcap;
  1111.     }
  1112.     while(*envnew) {
  1113.         if(tgetent(ptr, *envnew) == 1) {
  1114.             TermName = *envnew;
  1115.             if(!screen->TekEmu)
  1116.                 resize(screen, TermName, termcap, newtc);
  1117.             break;
  1118.         }
  1119.         envnew++;
  1120.     }
  1121.  
  1122.     if (get_ty) {
  1123.         screen->respond = loginpty;
  1124.         if((tslot = ttyslot()) <= 0)
  1125.             SysError(ERROR_TSLOT);
  1126. #ifdef TIOCCONS
  1127.         if (Console) {
  1128.             int on = 1;
  1129.             if (ioctl (0, TIOCCONS, &on) == -1)
  1130.                 SysError(ERROR_TIOCCONS);
  1131.         }
  1132. #endif TIOCCONS
  1133.     } else if (am_slave) {
  1134.         screen->respond = am_slave;
  1135.         ptydev[8] = ttydev[8] = passedPty[0];
  1136.         ptydev[9] = ttydev[9] = passedPty[1];
  1137.         if((tslot = ttyslot()) <= 0)
  1138.             SysError(ERROR_TSLOT2);
  1139.         setgid (screen->gid);
  1140.         setuid (screen->uid);
  1141.     } else {
  1142.         if ((tty = open ("/dev/tty", O_RDWR, 0)) < 0) {
  1143.             if (errno != ENXIO) SysError(ERROR_OPDEVTTY);
  1144.             else {
  1145.                 no_dev_tty = TRUE;
  1146.                 sg = d_sg;
  1147.                 tc = d_tc;
  1148.                 discipline = d_disipline;
  1149.                 ltc = d_ltc;
  1150.                 lmode = d_lmode;
  1151.             }
  1152.         } else {
  1153.             /* get a copy of the current terminal's state */
  1154.  
  1155.             if(ioctl(tty, TIOCGETP, &sg) == -1)
  1156.                 SysError (ERROR_TIOCGETP);
  1157.             if(ioctl(tty, TIOCGETC, &tc) == -1)
  1158.                 SysError (ERROR_TIOCGETC);
  1159.             if(ioctl(tty, TIOCGETD, &discipline) == -1)
  1160.                 SysError (ERROR_TIOCGETD);
  1161.             if(ioctl(tty, TIOCGLTC, <c) == -1)
  1162.                 SysError (ERROR_TIOCGLTC);
  1163.             if(ioctl(tty, TIOCLGET, &lmode) == -1)
  1164.                 SysError (ERROR_TIOCLGET);
  1165.             close (tty);
  1166.  
  1167.             /* close all std file descriptors */
  1168.             for (index1 = 0; index1 < 3; index1++)
  1169.                 close (index1);
  1170.             if ((tty = open ("/dev/tty", O_RDWR, 0)) < 0)
  1171.                 SysError (ERROR_OPDEVTTY2);
  1172.  
  1173.             if (ioctl (tty, TIOCNOTTY, 0) == -1)
  1174.                 SysError (ERROR_NOTTY);
  1175.             close (tty);
  1176.         }
  1177.  
  1178.         get_pty (&screen->respond, &tty);
  1179.  
  1180.         if (screen->respond != Xsocket + 1) {
  1181.             dup2 (screen->respond, Xsocket + 1);
  1182.             close (screen->respond);
  1183.             screen->respond = Xsocket + 1;
  1184.         }
  1185.  
  1186.         /* change ownership of tty to real group and user id */
  1187.         chown (ttydev, screen->uid, screen->gid);
  1188.  
  1189.         /* change protection of tty */
  1190.         chmod (ttydev, 0622);
  1191.  
  1192.         if (tty != Xsocket + 2)    {
  1193.             dup2 (tty, Xsocket + 2);
  1194.             close (tty);
  1195.             tty = Xsocket + 2;
  1196.         }
  1197.  
  1198.         /* set the new terminal's state to be the old one's 
  1199.            with minor modifications for efficiency */
  1200.  
  1201.         sg.sg_flags &= ~(ALLDELAY | XTABS | CBREAK | RAW);
  1202.         sg.sg_flags |= ECHO | CRMOD;
  1203.         /* make sure speed is set on pty so that editors work right*/
  1204.         sg.sg_ispeed = B9600;
  1205.         sg.sg_ospeed = B9600;
  1206.         /* reset t_brkc to default value */
  1207.         tc.t_brkc = -1;
  1208.  
  1209.         if (ioctl (tty, TIOCSETP, &sg) == -1)
  1210.             SysError (ERROR_TIOCSETP);
  1211.         if (ioctl (tty, TIOCSETC, &tc) == -1)
  1212.             SysError (ERROR_TIOCSETC);
  1213.         if (ioctl (tty, TIOCSETD, &discipline) == -1)
  1214.             SysError (ERROR_TIOCSETD);
  1215.         if (ioctl (tty, TIOCSLTC, <c) == -1)
  1216.             SysError (ERROR_TIOCSLTC);
  1217.         if (ioctl (tty, TIOCLSET, &lmode) == -1)
  1218.             SysError (ERROR_TIOCLSET);
  1219. #ifdef TIOCCONS
  1220.         if (Console) {
  1221.             int on = 1;
  1222.             if (ioctl (tty, TIOCCONS, &on) == -1)
  1223.                 SysError(ERROR_TIOCCONS);
  1224.         }
  1225. #endif TIOCCONS
  1226.  
  1227.         close (open ("/dev/null", O_RDWR, 0));
  1228.  
  1229.         for (index1 = 0; index1 < 3; index1++)
  1230.             dup2 (tty, index1);
  1231.         if((tslot = ttyslot()) <= 0)
  1232.             SysError(ERROR_TSLOT3);
  1233. #ifdef UTMP
  1234.         if((pw = getpwuid(screen->uid)) &&
  1235.          (i = open(etc_utmp, O_WRONLY)) >= 0) {
  1236.             bzero((char *)&utmp, sizeof(struct utmp));
  1237.             (void) strcpy(utmp.ut_line, &ttydev[5]);
  1238.             (void) strcpy(utmp.ut_name, pw->pw_name);
  1239.             (void) strcpy(utmp.ut_host, DisplayName());
  1240.             time(&utmp.ut_time);
  1241.             lseek(i, (long)(tslot * sizeof(struct utmp)), 0);
  1242.             write(i, (char *)&utmp, sizeof(struct utmp));
  1243.             close(i);
  1244.             added_utmp_entry = TRUE;
  1245.         }
  1246. #endif UTMP
  1247.     }
  1248.  
  1249. #ifdef sun
  1250. #ifdef TIOCSSIZE
  1251.     /* tell tty how big window is */
  1252.     if(screen->TekEmu) {
  1253.         ts.ts_lines = 38;
  1254.         ts.ts_cols = 81;
  1255.     } else {
  1256.         ts.ts_lines = screen->max_row + 1;
  1257.         ts.ts_cols = screen->max_col + 1;
  1258.     }
  1259.     ioctl (screen->respond, TIOCSSIZE, &ts);
  1260. #endif TIOCSSIZE
  1261. #else sun
  1262. #ifdef TIOCSWINSZ
  1263.     /* tell tty how big window is */
  1264.     if(screen->TekEmu) {
  1265.         ws.ws_row = 38;
  1266.         ws.ws_col = 81;
  1267.         ws.ws_xpixel = TFullWidth(screen);
  1268.         ws.ws_ypixel = TFullHeight(screen);
  1269.     } else {
  1270.         ws.ws_row = screen->max_row + 1;
  1271.         ws.ws_col = screen->max_col + 1;
  1272.         ws.ws_xpixel = FullWidth(screen);
  1273.         ws.ws_ypixel = FullHeight(screen);
  1274.     }
  1275.     ioctl (screen->respond, TIOCSWINSZ, &ws);
  1276. #endif TIOCSWINSZ
  1277. #endif sun
  1278.  
  1279.     if (!am_slave) {
  1280.         if ((screen->pid = fork ()) == -1)
  1281.         SysError (ERROR_FORK);
  1282.         
  1283.         if (screen->pid == 0) {
  1284.         extern char **environ;
  1285.         int pgrp = getpid();
  1286.         char shell_name[64];
  1287.  
  1288.         close (Xsocket);
  1289.         close (screen->respond);
  1290.         if(fileno(stderr) >= 3)
  1291.             close (fileno(stderr));
  1292.  
  1293.         if (tty >= 0) close (tty);
  1294.  
  1295.         signal (SIGCHLD, SIG_DFL);
  1296.         signal (SIGHUP, SIG_IGN);
  1297.  
  1298.         /* copy the environment before Setenving */
  1299.         for (i = 0 ; environ [i] != NULL ; i++) ;
  1300.         /*
  1301.          * The `4' is the number of Setenv() calls which may add
  1302.          * a new entry to the environment.  The `1' is for the
  1303.          * NULL terminating entry.
  1304.          */
  1305.         envnew = (char **) calloc (i + (4 + 1), sizeof(char *));
  1306.         bcopy((char *)environ, (char *)envnew, i * sizeof(char *));
  1307.         environ = envnew;
  1308.         Setenv ("TERM=", TermName);
  1309.         if(!TermName)
  1310.             *newtc = 0;
  1311.         Setenv ("TERMCAP=", newtc);
  1312.         sprintf(buf, "%d", screen->TekEmu ? (int)TWindow(screen) :
  1313.          (int)VWindow(screen));
  1314.         Setenv ("WINDOWID=", buf);
  1315.         /* put the display into the environment of the shell*/
  1316.         if (display[0] != '\0') 
  1317.             Setenv ("DISPLAY=", screen->display->displayname);
  1318.  
  1319.         signal(SIGTERM, SIG_DFL);
  1320.         ioctl(0, TIOCSPGRP, &pgrp);
  1321.         setpgrp (0, 0);
  1322.         close(open(ttyname(0), O_WRONLY, 0));
  1323.         setpgrp (0, pgrp);
  1324.  
  1325.         setgid (screen->gid);
  1326.         setuid (screen->uid);
  1327.  
  1328.         if (command_to_exec) {
  1329.             execvp(*command_to_exec, command_to_exec);
  1330.             /* print error message on screen */
  1331.             fprintf(stderr, "%s: Can't execvp %s\n", xterm_name,
  1332.              *command_to_exec);
  1333.         }
  1334.         signal(SIGHUP, SIG_IGN);
  1335.         if (get_ty) {
  1336.             ioctl (0, TIOCNOTTY, 0);
  1337.             execl ("/etc/getty", "+", "Xwindow", get_ty, 0);
  1338.         }
  1339.         signal(SIGHUP, SIG_DFL);
  1340.  
  1341. #ifdef UTMP
  1342.         if(((ptr = getenv("SHELL")) == NULL || *ptr == 0) &&
  1343.          ((pw == NULL && (pw = getpwuid(screen->uid)) == NULL) ||
  1344.          *(ptr = pw->pw_shell) == 0))
  1345. #else UTMP
  1346.         if(((ptr = getenv("SHELL")) == NULL || *ptr == 0) &&
  1347.          ((pw = getpwuid(screen->uid)) == NULL ||
  1348.          *(ptr = pw->pw_shell) == 0))
  1349. #endif UTMP
  1350.             ptr = "/bin/sh";
  1351.         if(shname = rindex(ptr, '/'))
  1352.             shname++;
  1353.         else
  1354.             shname = ptr;
  1355.         i = strlen(shname) - 3;
  1356.         ldisc = (strcmp("csh", shname + i) == 0 ||
  1357.          strcmp("ksh", shname + i) == 0) ? NTTYDISC : 0;
  1358.         ioctl(0, TIOCSETD, &ldisc);
  1359.         if(login_shell)
  1360.             strcpy(shell_name, "-");
  1361.         else
  1362.             *shell_name = 0;
  1363.         strcat(shell_name, shname);
  1364.         execl (ptr, shell_name, 0);
  1365.         fprintf (stderr, "%s: Could not exec %s!\n", xterm_name, ptr);
  1366.         sleep(5);
  1367.         exit(ERROR_EXEC);
  1368.         }
  1369.     }
  1370.  
  1371.     if(tty >= 0) close (tty);
  1372.     signal(SIGHUP,SIG_IGN);
  1373.  
  1374.     if (!no_dev_tty) {
  1375.         if ((tty = open ("/dev/tty", O_RDWR, 0)) < 0)
  1376.             SysError(ERROR_OPDEVTTY3);
  1377.         for (index1 = 0; index1 < 3; index1++)
  1378.             dup2 (tty, index1);
  1379.         if (tty > 2) close (tty);
  1380.     }
  1381.  
  1382.     signal(SIGINT, Exit);
  1383.     signal(SIGQUIT, Exit);
  1384.     signal(SIGTERM, Exit);
  1385. }
  1386.  
  1387. Exit(n)
  1388. int n;
  1389. {
  1390.     register Screen *screen = &term.screen;
  1391. #ifdef UTMP
  1392.     register int i;
  1393.     struct utmp utmp;
  1394.  
  1395.     if(added_utmp_entry && (i = open(etc_utmp, O_WRONLY)) >= 0) {
  1396.         bzero((char *)&utmp, sizeof(struct utmp));
  1397.         lseek(i, (long)(tslot * sizeof(struct utmp)), 0);
  1398.         write(i, (char *)&utmp, sizeof(struct utmp));
  1399.         close(i);
  1400.     }
  1401. #endif UTMP
  1402.     if(screen->logging)
  1403.         CloseLog(screen);
  1404.  
  1405.     if(!get_ty && !am_slave) {
  1406.         /* restore ownership of tty */
  1407.         chown (ttydev, 0, 0);
  1408.  
  1409.         /* restore modes of tty */
  1410.         chmod (ttydev, 0666);
  1411.     }
  1412.     exit(n);
  1413. }
  1414.  
  1415. resize(screen, TermName, oldtc, newtc)
  1416. Screen *screen;
  1417. char *TermName;
  1418. register char *oldtc, *newtc;
  1419. {
  1420.     register char *ptr1, *ptr2;
  1421.     register int i;
  1422.     register int li_first = 0;
  1423.     register char *temp;
  1424.     char *index(), *strindex();
  1425.  
  1426.     if ((ptr1 = strindex (oldtc, "co#")) == NULL){
  1427.         fprintf(stderr, "%s: Can't find co# in termcap string %s\n",
  1428.             xterm_name, TermName);
  1429.         exit (ERROR_NOCO);
  1430.     }
  1431.     if ((ptr2 = strindex (oldtc, "li#")) == NULL){
  1432.         fprintf(stderr, "%s: Can't find li# in termcap string %s\n",
  1433.             xterm_name, TermName);
  1434.         exit (ERROR_NOLI);
  1435.     }
  1436.     if(ptr1 > ptr2) {
  1437.         li_first++;
  1438.         temp = ptr1;
  1439.         ptr1 = ptr2;
  1440.         ptr2 = temp;
  1441.     }
  1442.     ptr1 += 3;
  1443.     ptr2 += 3;
  1444.     strncpy (newtc, oldtc, i = ptr1 - oldtc);
  1445.     newtc += i;
  1446.     sprintf (newtc, "%d", li_first ? screen->max_row + 1 :
  1447.      screen->max_col + 1);
  1448.     newtc += strlen(newtc);
  1449.     ptr1 = index (ptr1, ':');
  1450.     strncpy (newtc, ptr1, i = ptr2 - ptr1);
  1451.     newtc += i;
  1452.     sprintf (newtc, "%d", li_first ? screen->max_col + 1 :
  1453.      screen->max_row + 1);
  1454.     ptr2 = index (ptr2, ':');
  1455.     strcat (newtc, ptr2);
  1456. }
  1457.  
  1458. static reapchild ()
  1459. {
  1460.     union wait status;
  1461.     register int pid;
  1462.     
  1463. #ifdef DEBUG
  1464.     if (debug) fputs ("Exiting\n", stderr);
  1465. #endif DEBUG
  1466.     pid  = wait3 (&status, WNOHANG, NULL);
  1467.     if (!pid) return;
  1468.     if (pid != term.screen.pid) return;
  1469.     
  1470.     Cleanup(0);
  1471. }
  1472.  
  1473. consolepr(string)
  1474. char *string;
  1475. {
  1476.     extern int errno;
  1477.     extern char *sys_errlist[];
  1478.     int oerrno;
  1479.     int f;
  1480.  
  1481.     oerrno = errno;
  1482.     f = open("/dev/console",O_WRONLY);
  1483.     write(f, "xterm: ", 7);
  1484.     write(f, string, strlen(string));
  1485.     write(f, ": ", 2);
  1486.     write(f, sys_errlist[oerrno],strlen(sys_errlist[oerrno]));
  1487.     write(f, "\n", 1);
  1488.     close(f);
  1489.     if ((f = open("/dev/tty", 2)) >= 0) {
  1490.         ioctl(f, TIOCNOTTY, 0);
  1491.         close(f);
  1492.     }
  1493. }
  1494.  
  1495. checklogin()
  1496. {
  1497.     register int i, j;
  1498.     register struct passwd *pw;
  1499.     struct utmp utmp;
  1500.  
  1501.     if((i = open(etc_utmp, O_RDONLY)) < 0)
  1502.         return(FALSE);
  1503.     lseek(i, (long)(tslot * sizeof(struct utmp)), 0);
  1504.     j = read(i, (char *)&utmp, sizeof(utmp));
  1505.     close(i);
  1506.     if(j != sizeof(utmp) || strcmp(get_ty, utmp.ut_line) != 0 ||
  1507.      !*utmp.ut_name || (pw = getpwnam(utmp.ut_name)) == NULL)
  1508.         return(FALSE);
  1509.     chdir(pw->pw_dir);
  1510.     setgid(pw->pw_gid);
  1511.     setuid(pw->pw_uid);
  1512.     L_flag = 0;
  1513.     return(TRUE);
  1514. }
  1515. RAZZLE!DAZZLE
  1516. fi    # End main.c
  1517. if test -f menu.c
  1518. then
  1519.     echo shar: will not overwrite existing file "'menu.c'"
  1520. else
  1521. echo 'x - menu.c'
  1522. cat << \RAZZLE!DAZZLE > menu.c
  1523. /*
  1524.  *    $Source: /u1/X/xterm/RCS/menu.c,v $
  1525.  *    $Header: menu.c,v 10.101 86/12/01 17:52:43 swick Rel $
  1526.  */
  1527.  
  1528. #ifdef MODEMENU
  1529. #include "X/Xlib.h"
  1530. #include "menu.h"
  1531.  
  1532. #ifndef lint
  1533. static char sccs_id[] = "@(#)menu.c\tX10/6.6B\t12/26/86";
  1534. #endif    lint
  1535.  
  1536. #define    FALSE            0
  1537. #define    TRUE            1
  1538. #define    InvertPlane        1
  1539. #define    SetStateFlags(item)    item->itemFlags = (item->itemFlags &\
  1540.                  ~(itemStateMask | itemChanged)) |\
  1541.                  ((item->itemFlags & itemSetMask) >>\
  1542.                  itemSetMaskShift)
  1543.  
  1544.  
  1545. static short Check_MarkBits[] = {
  1546.    0x0100, 0x0180, 0x00c0, 0x0060,
  1547.    0x0031, 0x001b, 0x000e, 0x0004
  1548. };
  1549. static short Check_GrayBits[] = {
  1550.    0x0100, 0x0080, 0x0040, 0x0020,
  1551.    0x0011, 0x000a, 0x0004, 0x0000
  1552. };
  1553. static short Default_CursorBits[] = {
  1554.    0x0000, 0x0002, 0x0006, 0x000e,
  1555.    0x001e, 0x003e, 0x007e, 0x00fe,
  1556.    0x01fe, 0x003e, 0x0036, 0x0062,
  1557.    0x0060, 0x00c0, 0x00c0, 0x0000
  1558. };
  1559. static short Default_GrayBits[] = {
  1560.    0xaaaa, 0x5555, 0xaaaa, 0x5555,
  1561.    0xaaaa, 0x5555, 0xaaaa, 0x5555,
  1562.    0xaaaa, 0x5555, 0xaaaa, 0x5555,
  1563.    0xaaaa, 0x5555, 0xaaaa, 0x5555,
  1564. };
  1565. static short Default_MaskBits[] = {
  1566.    0x0003, 0x0007, 0x000f, 0x001f,
  1567.    0x003f, 0x007f, 0x00ff, 0x01ff,
  1568.    0x03ff, 0x07ff, 0x007f, 0x00f7,
  1569.    0x00f3, 0x01e1, 0x01e0, 0x01c0
  1570. };
  1571. static char def_menu_font[] = "vtsingle";
  1572.  
  1573. Pixmap Gray_Tile;
  1574. Menu Menu_Default;
  1575. Cursor Menu_DefaultCursor;
  1576. char *Menu_DefaultFont;
  1577. FontInfo *Menu_DefaultFontInfo;
  1578.  
  1579. /*
  1580.  * AddMenuItem() adds a menu item to an existing menu, at the end of the
  1581.  * list, which are number sequentially from zero.  The menuitem index is
  1582.  * return, or -1 if failed.
  1583.  */
  1584.  
  1585. AddMenuItem(menu, text)
  1586. register Menu *menu;
  1587. register char *text;
  1588. {
  1589.     register MenuItem *menuitem, **next;
  1590.     register int i;
  1591.     extern char *malloc();
  1592.  
  1593.     if(!menu || !text || (menuitem = (MenuItem *)malloc(sizeof(MenuItem)))
  1594.      == (MenuItem *)0)
  1595.         return(-1);
  1596.     bzero((char *)menuitem, sizeof(MenuItem));
  1597.     menuitem->itemText = text;
  1598.     menuitem->itemTextLength = strlen(text);
  1599.     for(i = 0, next = &menu->menuItems ; *next ; i++)
  1600.         next = &(*next)->nextItem;
  1601.     *next = menuitem;
  1602.     menu->menuFlags |= menuChanged;
  1603.     return(i);
  1604. }
  1605.  
  1606. /*
  1607.  * DisposeItem() releases the memory allocated for the given indexed
  1608.  * menuitem.  Nonzero is returned if an item was actual disposed of.
  1609.  */
  1610. DisposeItem(menu, i)
  1611. register Menu *menu;
  1612. register int i;
  1613. {
  1614.     register MenuItem **next, **last, *menuitem;
  1615.  
  1616.     if(!menu || i < 0)
  1617.         return(0);
  1618.     next = &menu->menuItems;
  1619.     do {
  1620.         if(!*next)
  1621.             return(0);
  1622.         last = next;
  1623.         next = &(*next)->nextItem;
  1624.     } while(i-- > 0);
  1625.     menuitem = *last;
  1626.     *last = *next;
  1627.     free(menuitem);
  1628.     return(1);
  1629. }
  1630.  
  1631. /*
  1632.  * DisposeMenu() releases the memory allocated for the given menu.
  1633.  */
  1634. DisposeMenu(menu)
  1635. register Menu *menu;
  1636. {
  1637.     static Unmap_Menu();
  1638.  
  1639.     if(!menu)
  1640.         return;
  1641.     if(menu->menuFlags & menuMapped)
  1642.         Unmap_Menu(menu);
  1643.     while(DisposeItem(menu, 0));
  1644.     if(menu->menuWindow)
  1645.         XDestroyWindow(menu->menuWindow);
  1646.     if(menu->menuSaved)
  1647.         XFreePixmap(menu->menuSaved);
  1648.     free(menu);
  1649. }
  1650.  
  1651. InitMenu(name)
  1652. register char *name;
  1653. {
  1654.     register char *cp;
  1655.     register Bitmap bit;
  1656.  
  1657.     /*
  1658.      * If the gray tile hasn't been set up, do it now.
  1659.      */
  1660.     if(!Gray_Tile) {
  1661.         if(!(bit = XStoreBitmap(grayWidth, grayHeight,
  1662.          Default_GrayBits)))
  1663.             return;
  1664.         Gray_Tile = XMakePixmap(bit, WhitePixel, BlackPixel);
  1665.         XFreeBitmap(bit);
  1666.     }
  1667.     Menu_Default.menuFlags = menuChanged;
  1668.     if((cp = XGetDefault(name, "MenuFreeze")) && strcmp(cp, "on") == 0)
  1669.         Menu_Default.menuFlags |= menuFreeze;
  1670.     if((cp = XGetDefault(name, "MenuSave")) && strcmp(cp, "on") == 0)
  1671.         Menu_Default.menuFlags |= menuSaveMenu;
  1672.     Menu_Default.menuInitialItem = -1;
  1673.     Menu_Default.menuBorderWidth = (cp = XGetDefault(name, "MenuBorder")) ?
  1674.      atoi(cp) : 2;
  1675.     Menu_Default.menuItemPad = (cp = XGetDefault(name, "MenuPad")) ?
  1676.      atoi(cp) : 3;
  1677.     Menu_DefaultFont = (cp = XGetDefault(name, "MenuFont")) ? cp :
  1678.      def_menu_font;
  1679. };
  1680.  
  1681. /*
  1682.  * ItemFlags returns the state of item "n" of the menu.
  1683.  */
  1684. ItemFlags(menu, n)
  1685. register Menu *menu;
  1686. register int n;
  1687. {
  1688.     register MenuItem *item;
  1689.  
  1690.     if(!menu || !menu->menuItems || n < 0)
  1691.         return(-1);
  1692.     for(item = menu->menuItems ; n > 0 ; n--)
  1693.         if(!(item = item->nextItem))
  1694.             return(0);
  1695.     return((item->itemFlags & itemSetMask) >> itemSetMaskShift);
  1696. }
  1697.  
  1698. /*
  1699.  * ItemText changes the text of item "n" of the menu.
  1700.  */
  1701. ItemText(menu, n, text)
  1702. register Menu *menu;
  1703. register int n;
  1704. char *text;
  1705. {
  1706.     register MenuItem *item;
  1707.  
  1708.     if(!menu || !menu->menuItems || n < 0 || !text)
  1709.         return(0);
  1710.     for(item = menu->menuItems ; n > 0 ; n--)
  1711.         if(!(item = item->nextItem))
  1712.             return(0);
  1713.     item->itemText = text;
  1714.     menu->menuFlags |= menuChanged;
  1715.     return(1);
  1716. }
  1717.  
  1718. /*
  1719.  * NewMenu() returns a pointer to an initialized new Menu structure, or NULL
  1720.  * if failed.
  1721.  *
  1722.  * The Menu structure _menuDefault contains the default menu settings.
  1723.  */
  1724. Menu *NewMenu(name, reverse)
  1725. char *name;
  1726. int reverse;
  1727. {
  1728.     register Menu *menu;
  1729.     register int fg, bg;
  1730.     extern char *malloc();
  1731.  
  1732.     /*
  1733.      * If the GrayTile hasn't been defined, InitMenu() was never
  1734.      * run, so exit.
  1735.      */
  1736.     if(!Gray_Tile)
  1737.         return((Menu *)0);
  1738.     /*
  1739.      * Allocate the memory for the menu structure.
  1740.      */
  1741.     if((menu = (Menu *)malloc(sizeof(Menu))) == (Menu *)0)
  1742.         return((Menu *)0);
  1743.     /*
  1744.      * Initialize to default values.
  1745.      */
  1746.     *menu = Menu_Default;
  1747.     /*
  1748.      * If the menu font hasn't yet been gotten, go get it.
  1749.      */
  1750.     if(!menu->menuFontInfo) {
  1751.         if(!Menu_DefaultFontInfo && !(Menu_DefaultFontInfo =
  1752.          XOpenFont(Menu_DefaultFont)))
  1753.             return((Menu *)0);
  1754.         menu->menuFontInfo = Menu_DefaultFontInfo;
  1755.     }
  1756.     /*
  1757.      * If the menu cursor hasn't been given, make a default one.
  1758.      */
  1759.     if(!menu->menuCursor) {
  1760.         if(!Menu_DefaultCursor) {
  1761.             if(reverse) {
  1762.                 fg = WhitePixel;
  1763.                 bg = BlackPixel;
  1764.             } else {
  1765.                 fg = BlackPixel;
  1766.                 bg = WhitePixel;
  1767.             }
  1768.             if(!(Menu_DefaultCursor =
  1769.              XCreateCursor(defaultCursorWidth, defaultCursorHeight,
  1770.               Default_CursorBits, Default_MaskBits, defaultCursorX,
  1771.               defaultCursorY, fg, bg, GXcopy)))
  1772.                 return((Menu *)0);
  1773.         }
  1774.         menu->menuCursor = Menu_DefaultCursor;
  1775.     }
  1776.     /*
  1777.      * Initialze the default background and border pixmaps and foreground
  1778.      * and background colors (black and white).
  1779.      */
  1780.     if(reverse) {
  1781.         menu->menuBgTile = BlackPixmap;
  1782.         menu->menuFgColor = WhitePixel;
  1783.         menu->menuBgColor = BlackPixel;
  1784.     } else {
  1785.         menu->menuBgTile = WhitePixmap;
  1786.         menu->menuFgColor = BlackPixel;
  1787.         menu->menuBgColor = WhitePixel;
  1788.     }
  1789.     /*
  1790.      * Set the menu title.  If name is NULL or is an empty string, no
  1791.      * title will be displayed.
  1792.      */
  1793.     if(name && *name) {
  1794.         menu->menuTitleLength = strlen(menu->menuTitle = name);
  1795.         menu->menuTitleWidth = XStringWidth(name, menu->menuFontInfo,
  1796.          0, 0);
  1797.         menu->menuItemTop = menu->menuFontInfo->height + 2 *
  1798.          menu->menuItemPad + 1;
  1799.     } else
  1800.         menu->menuTitleLength = menu->menuTitleWidth =
  1801.          menu->menuItemTop = 0;
  1802.     return(menu);
  1803. }
  1804.  
  1805. /*
  1806.  * SetItemCheck sets the check state of item "n" of the menu to "state".
  1807.  */
  1808. SetItemCheck(menu, n, state)
  1809. register Menu *menu;
  1810. register int n;
  1811. int state;
  1812. {
  1813.     register MenuItem *item;
  1814.  
  1815.     if(!menu || !menu->menuItems || n < 0)
  1816.         return(0);
  1817.     for(item = menu->menuItems ; n > 0 ; n--)
  1818.         if(!(item = item->nextItem))
  1819.             return(0);
  1820.     if(state)
  1821.         item->itemFlags |= itemSetChecked;
  1822.     else
  1823.         item->itemFlags &= ~itemSetChecked;
  1824.     if(((item->itemFlags & itemSetMask) >> itemSetMaskShift) !=
  1825.      (item->itemFlags & itemStateMask)) {
  1826.         item->itemFlags |= itemChanged;
  1827.         menu->menuFlags |= menuItemChanged;
  1828.     } else
  1829.         item->itemFlags &= ~itemChanged;
  1830.     return(1);
  1831. }
  1832.  
  1833. /*
  1834.  * SetItemDisable sets the disable state of item "n" of the menu to "state".
  1835.  */
  1836. SetItemDisable(menu, n, state)
  1837. register Menu *menu;
  1838. register int n;
  1839. int state;
  1840. {
  1841.     register MenuItem *item;
  1842.  
  1843.     if(!menu || !menu->menuItems || n < 0)
  1844.         return(0);
  1845.     for(item = menu->menuItems ; n > 0 ; n--)
  1846.         if(!(item = item->nextItem))
  1847.             return(0);
  1848.     if(state)
  1849.         item->itemFlags |= itemSetDisabled;
  1850.     else
  1851.         item->itemFlags &= ~itemSetDisabled;
  1852.     if(((item->itemFlags & itemSetMask) >> itemSetMaskShift) !=
  1853.      (item->itemFlags & itemStateMask)) {
  1854.         item->itemFlags |= itemChanged;
  1855.         menu->menuFlags |= menuItemChanged;
  1856.     } else
  1857.         item->itemFlags &= ~itemChanged;
  1858.     return(1);
  1859. }
  1860.  
  1861. /*
  1862.  * TrackMenu does most of the work of displaying the menu and tracking the
  1863.  * mouse.
  1864.  */
  1865. TrackMenu(menu, event)
  1866. register Menu *menu;
  1867. register XButtonPressedEvent *event;
  1868. {
  1869.     register MenuItem *item;
  1870.     register int i, button;
  1871.     register MenuItem *hilited_item = (MenuItem *)0;
  1872.     register int drawn;
  1873.     XButtonReleasedEvent ev;
  1874.     register int changed;
  1875.     int y, n, hilited_y, hilited_n, in_window;
  1876.     static MenuItem *Mouse_InItem(), *Y_InItem();
  1877.     static Unmap_Menu();
  1878.  
  1879.     /*
  1880.      * Check that things are reasonable.
  1881.      */
  1882.     if(!menu || !event || !menu->menuItems || event->type != ButtonPressed)
  1883.         return(-1);
  1884.     /*
  1885.      * Set the changed flag and clear the menu changed flags.
  1886.      */
  1887.     changed = menu->menuFlags & (menuChanged | menuItemChanged);
  1888.     /*
  1889.      * If the entire menu has changed, throw away any saved pixmap and
  1890.      * then call RecalcMenu().
  1891.      */
  1892.     if(changed & menuChanged) {
  1893.         if(menu->menuSaved)
  1894.             XFreePixmap(menu->menuSaved);
  1895.         menu->menuSaved = (Pixmap)0;
  1896.         if(!Recalc_Menu(menu))
  1897.             return(-1);
  1898.         changed &= ~menuItemChanged;
  1899.     }
  1900.     /*
  1901.      * Now if the window was never created, go ahead and make it.  Otherwise
  1902.      * if the menu has changed, resize the window.
  1903.      */
  1904.     if(!menu->menuWindow) {
  1905.         if((menu->menuWindow = XCreateWindow(RootWindow, 0, 0,
  1906.          menu->menuWidth, menu->menuHeight, menu->menuBorderWidth,
  1907.          Gray_Tile, menu->menuBgTile)) == (Window)0)
  1908.             return(-1);
  1909.         XDefineCursor(menu->menuWindow, menu->menuCursor);
  1910.         XSelectInput(menu->menuWindow, ExposeWindow | EnterWindow |
  1911.          LeaveWindow | MouseMoved | ButtonReleased);
  1912.     } else if(changed & menuChanged)
  1913.          XChangeWindow(menu->menuWindow, menu->menuWidth,
  1914.          menu->menuHeight);
  1915.     /*
  1916.      * Figure out where the menu is supposed to go, from the initial button
  1917.      * press, and move the window there.  Then map the menu.
  1918.      */
  1919.     if(!Move_Menu(menu, event) || !Map_Menu(menu))
  1920.         return(-1);
  1921.     /*
  1922.      * Try to grab the mouse, over a period of 10 seconds.
  1923.      */
  1924.     for(i = 10 ; ; ) {
  1925.         if(XGrabMouse(menu->menuWindow, menu->menuCursor,
  1926.          ButtonReleased | EnterWindow | LeaveWindow | MouseMoved))
  1927.             break;
  1928.         if(--i <= 0) {
  1929.             Unmap_Menu(menu);
  1930.             return(-1);
  1931.         }
  1932.         sleep(1);
  1933.     }
  1934.     /*
  1935.      * Save away the button that was pressed and use it to match a
  1936.      * corresponding ButtonReleased event.
  1937.      */
  1938.     button = event->detail & 03;
  1939.     /*
  1940.      * Now process events for the menu window.
  1941.      */
  1942.     drawn = 0;
  1943.     for( ; ; ) {
  1944.         XNextEvent(&ev);
  1945.         if(ev.type != ButtonReleased && ev.window != menu->menuWindow) {
  1946.             if(menu->menuEventHandler)
  1947.                 (*menu->menuEventHandler)(&ev);
  1948.             continue;
  1949.         }
  1950.         switch(ev.type) {
  1951.          case ExposeWindow:
  1952.             /*
  1953.              * If we have a saved pixmap, display it.  Otherwise
  1954.              * redraw the menu and save it away.
  1955.              */
  1956.             if(menu->menuSaved) {
  1957.                 XPixmapPut(menu->menuWindow, 0, 0, 0, 0,
  1958.                  menu->menuWidth, menu->menuHeight,
  1959.                  menu->menuSaved, GXcopy, AllPlanes);
  1960.                 /*
  1961.                  * If the menuItemChanged flag is still set,
  1962.                  * then we need to redraw certain menu items.
  1963.                  * ("i" is the vertical position of the top
  1964.                  * of the current item.)
  1965.                  */
  1966.                 if(changed & menuItemChanged) {
  1967.                     i = menu->menuItemTop;
  1968.                     for(item = menu->menuItems ; item ;
  1969.                      item = item->nextItem) {
  1970.                         if(item->itemFlags &
  1971.                          itemChanged)
  1972.                             Modify_Item(menu, item,
  1973.                              i);
  1974.                         i += item->itemHeight;
  1975.                     }
  1976.                 }
  1977.             } else
  1978.                 Draw_Menu(menu);
  1979.             /*
  1980.              * If the menu has changed in any way and we want to
  1981.              * save the menu, throw away any existing save menu
  1982.              * image and make a new one.
  1983.              */
  1984.             XFlush();
  1985.             if(changed && (menu->menuFlags & menuSaveMenu)) {
  1986.                 if(menu->menuSaved)
  1987.                     XFreePixmap(menu->menuSaved);
  1988.                 menu->menuSaved = XPixmapSave(menu->menuWindow,
  1989.                  0, 0, menu->menuWidth, menu->menuHeight);
  1990.             }
  1991.             /*
  1992.              * See which item the cursor may currently be in.  If
  1993.              * it is in a non-disabled item, hilite it.
  1994.              */
  1995.             if(hilited_item = Mouse_InItem(menu, &hilited_y,
  1996.              &hilited_n, &in_window))
  1997.                 XPixFill(menu->menuWindow, 0, hilited_y,
  1998.                  menu->menuWidth, hilited_item->itemHeight,
  1999.                  BlackPixmap, (Bitmap)0, GXinvert, InvertPlane);
  2000.             drawn++;
  2001.             break;
  2002.          case EnterWindow:
  2003.             in_window = TRUE;
  2004.             /* drop through */
  2005.          case MouseMoved:
  2006.             if(!drawn || !in_window)
  2007.                 break;
  2008.             /*
  2009.              * See which item the cursor may currently be in.  If
  2010.              * the item has changed, unhilite the old one and
  2011.              * then hilited the new one.
  2012.              */
  2013.             y = ((XEnterWindowEvent *)&ev)->y;
  2014.             if((item = Y_InItem(menu, &y, &n)) != hilited_item) {
  2015.                 if(hilited_item)
  2016.                     XPixFill(menu->menuWindow, 0,
  2017.                      hilited_y, menu->menuWidth,
  2018.                      hilited_item->itemHeight, BlackPixmap,
  2019.                      (Bitmap)0, GXinvert, InvertPlane);
  2020.                 if(hilited_item = item) {
  2021.                     XPixFill(menu->menuWindow, 0,
  2022.                      hilited_y = y, menu->menuWidth,
  2023.                      item->itemHeight, BlackPixmap,
  2024.                      (Bitmap)0, GXinvert, InvertPlane);
  2025.                     hilited_n = n;
  2026.                 }
  2027.             }
  2028.             break;
  2029.          case LeaveWindow:
  2030.             if(!drawn)
  2031.                 break;
  2032.             /*
  2033.              * Unhilite any window that is currently hilited.
  2034.              */
  2035.             if(hilited_item) {
  2036.                 XPixFill(menu->menuWindow, 0, hilited_y,
  2037.                  menu->menuWidth, hilited_item->itemHeight,
  2038.                  BlackPixmap, (Bitmap)0, GXinvert, InvertPlane);
  2039.                 hilited_item = (MenuItem *)0;
  2040.             }
  2041.             in_window = FALSE;
  2042.             break;
  2043.          case ButtonReleased:
  2044.             /*
  2045.              * If the correct button was released, ungrab the mouse
  2046.              * and return the index number of any selected menu
  2047.              * item.
  2048.              */
  2049.             if((ev.detail & 0x3) == button) {
  2050.                 if(in_window) {
  2051.                     y = ((XButtonReleasedEvent *)&ev)->y;
  2052.                     if((item = Y_InItem(menu, &y, &n)) !=
  2053.                      hilited_item) {
  2054.                         if(hilited_item)
  2055.                         XPixFill(menu->menuWindow, 0,
  2056.                          hilited_y, menu->menuWidth,
  2057.                          hilited_item->itemHeight,
  2058.                          BlackPixmap, (Bitmap)0,
  2059.                          GXinvert, InvertPlane);
  2060.                         if(hilited_item = item) {
  2061.                         XPixFill(menu->menuWindow, 0,
  2062.                          hilited_y = y, menu->menuWidth,
  2063.                          hilited_item->itemHeight,
  2064.                          BlackPixmap, (Bitmap)0,
  2065.                          GXinvert, InvertPlane);
  2066.                         hilited_n = n;
  2067.                         }
  2068.                     }
  2069.                 }
  2070.                 XUngrabMouse();
  2071.                 menu->menuFlags &= ~(menuChanged |
  2072.                  menuItemChanged);
  2073.                 Unmap_Menu(menu);
  2074.                 XFlush();
  2075.                 if(hilited_item)
  2076.                     return(menu->menuInitialItem =
  2077.                      hilited_n);
  2078.                 return(-1);
  2079.             }
  2080.             break;
  2081.         }
  2082.     }
  2083. }
  2084.  
  2085. /*
  2086.  * Recalculate all of the various menu and item variables.
  2087.  */
  2088. static Recalc_Menu(menu)
  2089. register Menu *menu;
  2090. {
  2091.     register MenuItem *item;
  2092.     register int max, i, height, fontheight;
  2093.  
  2094.     /*
  2095.      * We must have already gotten the menu font.
  2096.      */
  2097.     if(!menu->menuFontInfo)
  2098.         return(0);
  2099.     /*
  2100.      * Initialize the various max width variables.
  2101.      */
  2102.     fontheight = menu->menuFontInfo->height;
  2103.     height = menu->menuItemTop;
  2104.     menu->menuMaxTextWidth = menu->menuTitleWidth;
  2105.     /*
  2106.      * The item height is the maximum of the font height and the
  2107.      * checkbox height.
  2108.      */
  2109.     max = fontheight;
  2110.     if(checkMarkHeight > max)
  2111.         max = checkMarkHeight;
  2112.     /*
  2113.      * Go through the menu item list.
  2114.      */
  2115.     for(item = menu->menuItems ; item ; item = item->nextItem) {
  2116.         /*
  2117.          * If the item text is a single dash, we assume this is
  2118.          * a line separator and treat it special.
  2119.          */
  2120.         if(strcmp(item->itemText, "-") == 0)
  2121.             height += (item->itemHeight = lineSeparatorHeight);
  2122.         else {
  2123.             height += (item->itemHeight = max);
  2124.             /*
  2125.              * Check the text width with the max value stored in
  2126.              * menu.
  2127.              */
  2128.             if((item->itemTextWidth = XStringWidth(item->itemText,
  2129.              menu->menuFontInfo, 0, 0)) > menu->menuMaxTextWidth)
  2130.                 menu->menuMaxTextWidth = item->itemTextWidth;
  2131.         }
  2132.         /*
  2133.          * If the itemChanged flag is set, set the state bits.
  2134.          */
  2135.         if(item->itemFlags & itemChanged) {
  2136.             item->itemFlags = (item->itemFlags & ~itemStateMask) |
  2137.              ((item->itemFlags & itemSetMask) >> itemSetMaskShift);
  2138.             item->itemFlags &= ~itemChanged;
  2139.         }
  2140.     }
  2141.     /*
  2142.      * Set the menu height and then set the menu width.
  2143.      */
  2144.     menu->menuHeight = height;
  2145.     menu->menuWidth = 3 * menu->menuItemPad + menu->menuMaxTextWidth +
  2146.      checkMarkWidth;
  2147.     return(1);
  2148. }
  2149.  
  2150. /*
  2151.  * Figure out where to popup the menu, relative to the where the button was
  2152.  * pressed.
  2153.  */
  2154. static Move_Menu(menu, ev)
  2155. register Menu *menu;
  2156. XButtonPressedEvent *ev;
  2157. {
  2158.     register MenuItem *item;
  2159.     register int n, x, y;
  2160.     int ev_x, ev_y;
  2161.     int total_width;
  2162.     Window subw;
  2163.  
  2164.     /*
  2165.      * Get the coordinates of the mouse when the button was pressed.
  2166.      */
  2167.     XInterpretLocator(RootWindow, &ev_x, &ev_y, &subw, ev->location);
  2168.     /*
  2169.      * Try to popup the menu so that the cursor is centered within the
  2170.      * width of the menu, but compensate if that would run it outside
  2171.      * the display area.
  2172.      */
  2173.     total_width = menu->menuWidth + 2 * menu->menuBorderWidth;
  2174.     if((x = ev_x - total_width / 2) < 0)
  2175.         x = 0;
  2176.     else if(x + total_width > DisplayWidth())
  2177.         x = DisplayWidth() - total_width;
  2178. #ifdef DROPMENUS
  2179.     y = 0;
  2180. #else DROPMENUS
  2181.     /*
  2182.      * If we have an inital item, try to popup the menu centered
  2183.      * vertically within this item.
  2184.      */
  2185.     if(menu->menuInitialItem >= 0) {
  2186.         /*
  2187.          * Look through the item list. "y" is the vertical position
  2188.          * of the top of the current item and "n" is the item number.
  2189.          */
  2190.         y = menu->menuItemTop + menu->menuBorderWidth;
  2191.         for(n = 0, item = menu->menuItems ; ; n++) {
  2192.             /*
  2193.              * On finding the intial item, center within this item.
  2194.              */
  2195.             if(n == menu->menuInitialItem) {
  2196.                 y += item->itemHeight / 2;
  2197.                 break;
  2198.             }
  2199.             y += item->itemHeight;
  2200.             /*
  2201.              * If we run out of items, turn off the initial item
  2202.              * and treat this as if no initial item.
  2203.              */
  2204.             if(!(item = item->nextItem)) {
  2205.                 menu->menuInitialItem = -1;
  2206.                 goto noInitial;
  2207.             }
  2208.         }
  2209.     /*
  2210.      * If no initial item, try to popup the menu centered in the item
  2211.      * nearest the center of the menu.
  2212.      */
  2213.     } else {
  2214. noInitial:
  2215.         /*
  2216.          * Look through the item list. "y" is the vertical position
  2217.          * of the top of the current item and "n" is the vertical
  2218.          * position of the center of the menu.
  2219.          */
  2220.         y = menu->menuItemTop + menu->menuBorderWidth;
  2221.         for(n = menu->menuHeight / 2, item = menu->menuItems ; item ;
  2222.          item = item->nextItem)
  2223.             /*
  2224.              * If the center of the menu is in this item, we
  2225.              * center within this item.
  2226.              */
  2227.             if((y += item->itemHeight) > n) {
  2228.                 y -= item->itemHeight / 2;
  2229.                 break;
  2230.             }
  2231.     }
  2232. #endif DROPMENU
  2233.     /*
  2234.      * If the menu extends above outside of the display, warp
  2235.      * the mouse vertically so the menu will all show up.
  2236.      */
  2237.     if((y = ev_y - y) < 0) {
  2238.         XWarpMouse(RootWindow, ev_x, ev_y - y);
  2239.         y = 0;
  2240.     } else if((n = y + menu->menuHeight + 2 * menu->menuBorderWidth
  2241.                - DisplayHeight()) > 0) {
  2242.         XWarpMouse(RootWindow, ev_x, ev_y - n);
  2243.         y -= n;
  2244.     }
  2245.     XMoveWindow(menu->menuWindow, x, y);
  2246.     /*
  2247.      * If we are in freeze mode, save what will be the coordinates of
  2248.      * the save image.
  2249.      */
  2250.     if(menu->menuFlags & menuFreeze) {
  2251.         menu->menuSavedImageX = x;
  2252.         menu->menuSavedImageY = y;
  2253.     }
  2254.     return(1);
  2255. }
  2256.  
  2257. /*
  2258.  * Map the menu window.
  2259.  */
  2260. static Map_Menu(menu)
  2261. register Menu *menu;
  2262. {
  2263.     register int i;
  2264.  
  2265.     /*
  2266.      * If we are in freeze mode, save the pixmap underneath where the menu
  2267.      * will be (including the border).
  2268.      */
  2269.     if(menu->menuFlags & menuFreeze) {
  2270.         XGrabServer();
  2271.         i = 2 * menu->menuBorderWidth;
  2272.         if((menu->menuSavedImage = XPixmapSave(RootWindow,
  2273.          menu->menuSavedImageX, menu->menuSavedImageY, menu->menuWidth
  2274.          + i, menu->menuHeight + i)) == (Pixmap)0)
  2275.             return(0);
  2276.     }
  2277.     /*
  2278.      * Actually map the window.
  2279.      */
  2280.     XMapWindow(menu->menuWindow);
  2281.     menu->menuFlags |= menuMapped;
  2282.     return(1);
  2283. }
  2284.  
  2285. /*
  2286.  * Draw the entire menu in the blank window.
  2287.  */
  2288. static Draw_Menu(menu)
  2289. register Menu *menu;
  2290. {
  2291.     register MenuItem *item;
  2292.     register int top = menu->menuItemTop;
  2293.     register int x = menu->menuItemPad;
  2294.     register int y, dim;
  2295.  
  2296.     /*
  2297.      * If we have a menu title, draw it first, centered and hilited.
  2298.      */
  2299.     if(menu->menuTitleLength) {
  2300.         XPixSet(menu->menuWindow, 0, 0, menu->menuWidth,
  2301.          top - 1, menu->menuFgColor);
  2302.         XText(menu->menuWindow, (menu->menuWidth -
  2303.          menu->menuTitleWidth) / 2, menu->menuItemPad, menu->menuTitle,
  2304.          menu->menuTitleLength, menu->menuFontInfo->id,
  2305.          menu->menuBgColor, menu->menuFgColor);
  2306.     }
  2307.     /*
  2308.      * For each item in the list, first draw any check mark and then
  2309.      * draw the rest of it.
  2310.      */
  2311.     for(item = menu->menuItems ; item ; item = item->nextItem) {
  2312.         SetStateFlags(item);
  2313.         dim = (item->itemFlags & itemDisabled);
  2314.         /*
  2315.          * Draw the check mark, possibly dimmed, wherever is necessary.
  2316.          */
  2317.         if(item->itemFlags & itemChecked) {
  2318.             XBitmapBitsPut(menu->menuWindow, x, y = top +
  2319.              (item->itemHeight - checkMarkHeight) / 2,
  2320.              checkMarkWidth, checkMarkHeight, dim ? Check_GrayBits :
  2321.              Check_MarkBits, menu->menuFgColor, menu->menuBgColor,
  2322.              (Bitmap)0, GXcopy, AllPlanes);
  2323.         }
  2324.         /*
  2325.          * Draw the item, possibly dimmed.
  2326.          */
  2327.         Draw_Item(menu, item, top, dim);
  2328.         top += item->itemHeight;
  2329.     }
  2330. }
  2331.  
  2332. /*
  2333.  * Modify the item at vertical position y.  This routine is table driven and
  2334.  * the state and set bits are each 2 bits long, contiguous, the least
  2335.  * significant bits in the flag word and with the state bits in bits 0 & 1.
  2336.  */
  2337.  
  2338. #define    drawCheck    0x10
  2339. #define    removeCheck    0x08
  2340. #define    dimCheck    0x04
  2341. #define    drawItem    0x02
  2342. #define    dimItem        0x01
  2343.  
  2344. static char Modify_Table[] = {
  2345.     0x00, 0x02, 0x08, 0x0a, 0x01, 0x00, 0x09, 0x08,
  2346.     0x10, 0x12, 0x00, 0x12, 0x15, 0x14, 0x05, 0x00
  2347. };
  2348.     
  2349. static Modify_Item(menu, item, top)
  2350. register Menu *menu;
  2351. register MenuItem *item;
  2352. int top;
  2353. {
  2354.     register int x = menu->menuItemPad;
  2355.     register int y;
  2356.     register int center = top + item->itemHeight / 2;
  2357.     register int func = Modify_Table[item->itemFlags &
  2358.      (itemStateMask | itemSetMask)];
  2359.  
  2360.     /*
  2361.      * If we really won't be making a change, return.
  2362.      */
  2363.     if(func == 0)
  2364.         return;
  2365.     /*
  2366.      * Draw the check mark if needed, possibly dimmed.
  2367.      */
  2368.     y = center - (checkMarkHeight / 2);
  2369.     if(func & (drawCheck | dimCheck))
  2370.         XBitmapBitsPut(menu->menuWindow, x, y, checkMarkWidth,
  2371.          checkMarkHeight, (func & dimCheck) ? Check_GrayBits :
  2372.          Check_MarkBits, menu->menuFgColor, menu->menuBgColor,
  2373.          (Bitmap)0, GXcopy, AllPlanes);
  2374.     /*
  2375.      * Remove the check mark if needed.
  2376.      */
  2377.     if(func & removeCheck)
  2378.         XTileSet(menu->menuWindow, x, y, checkMarkWidth,
  2379.          checkMarkHeight, menu->menuBgTile);
  2380.     /*
  2381.      * Call Draw_Item if we need to draw or dim the item.
  2382.      */
  2383.     if((x = func & dimItem) || (func & drawItem))
  2384.         Draw_Item(menu, item, top, x);
  2385.     /*
  2386.      * Update state flags.
  2387.      */
  2388.     SetStateFlags(item);
  2389. }
  2390.  
  2391. /*
  2392.  * Draw the item (less check mark) at vertical position y.
  2393.  * Dim the item if "dim" is set.
  2394.  */
  2395. static Draw_Item(menu, item, y, dim)
  2396. register Menu *menu;
  2397. register MenuItem *item;
  2398. register int y;
  2399. int  dim;
  2400. {
  2401.     register int x = 2 * menu->menuItemPad + checkMarkWidth;
  2402.     register int center = y + item->itemHeight / 2;
  2403.  
  2404.     /*
  2405.      * If the item text is a single dash, draw a separating line.
  2406.      */
  2407.     if(strcmp(item->itemText, "-") == 0) {
  2408.         XLine(menu->menuWindow, 0, center, menu->menuWidth, center,
  2409.          1, 1, menu->menuFgColor, GXcopy, AllPlanes);
  2410.         return;
  2411.     }
  2412.     /*
  2413.      * Draw and/or dim the text, centered vertically.
  2414.      */
  2415.     y = center - (menu->menuFontInfo->height / 2);
  2416.     if(dim) {
  2417.         XTileSet(menu->menuWindow, x, y, item->itemTextWidth,
  2418.          menu->menuFontInfo->height, Gray_Tile);
  2419.         XTextPad(menu->menuWindow, x, y, item->itemText,
  2420.          item->itemTextLength, menu->menuFontInfo->id, 0, 0,
  2421.          menu->menuFgColor, menu->menuBgColor, menu->menuFgColor ?
  2422.          GXand : GXor, AllPlanes);
  2423.     } else
  2424.         XText(menu->menuWindow, x, y, item->itemText,
  2425.          item->itemTextLength, menu->menuFontInfo->id,
  2426.          menu->menuFgColor, menu->menuBgColor);
  2427. }
  2428.  
  2429. /*
  2430.  * Determine which enabled menu item the mouse is currently in.  Return the
  2431.  * top position of this item and its item number.  Set inwindow to whether
  2432.  * we are or not.
  2433.  */
  2434. static MenuItem *Mouse_InItem(menu, top, n, inwindow)
  2435. register Menu *menu;
  2436. int *top, *n, *inwindow;
  2437. {
  2438.     int x, y;
  2439.     Window subw;
  2440.     static MenuItem *Y_InItem();
  2441.  
  2442.     /*
  2443.      * Find out where the mouse is.  If its not in the menu window,
  2444.      * return NULL.
  2445.      */
  2446.     XQueryMouse(RootWindow, &x, &y, &subw);
  2447.     if(subw != menu->menuWindow) {
  2448.         *inwindow = FALSE;
  2449.         return((MenuItem *)0);
  2450.     }
  2451.     *inwindow = TRUE;
  2452.     /*
  2453.      * Now get the coordinates relative to the menu window.
  2454.      */
  2455.     XInterpretLocator(menu->menuWindow, &x, &y, &subw, (x << 16) | y);
  2456.     /*
  2457.      * Call Y_InItem().
  2458.      */
  2459.     *top = y;
  2460.     return(Y_InItem(menu, top, n));
  2461. }
  2462.  
  2463. /*
  2464.  * Return which enabled item the locator is in.  Also return the
  2465.  * top position of this item and its item number.  Initial y passed
  2466.  * in top.
  2467.  */
  2468. static MenuItem *Y_InItem(menu, top, n)
  2469. register Menu *menu;
  2470. int *top, *n;
  2471. {
  2472.     register MenuItem *item;
  2473.     register int t, i;
  2474.     register int y = *top;
  2475.     Window subw;
  2476.  
  2477.     /*
  2478.      * Go through the item list.  "t" is the vertical position of the
  2479.      * current item and "i" is its item number.
  2480.      */
  2481.     t = menu->menuItemTop;
  2482.     /*
  2483.      * If the mouse is before the first item, return.
  2484.      */
  2485.     if(y < t)
  2486.         return((MenuItem *)0);
  2487.     for(i = 0, item = menu->menuItems ; item ; i++, item = item->nextItem) {
  2488.         /*
  2489.          * If the y coordinate is within this menu item, then return.
  2490.          * But don't return disable items.
  2491.          */
  2492.         if(t + item->itemHeight > y) {
  2493.             if(item->itemFlags & itemDisabled)
  2494.                 return((MenuItem *)0);
  2495.             *top = t;
  2496.             *n = i;
  2497.             return(item);
  2498.         }
  2499.         t += item->itemHeight;
  2500.     }
  2501.     /*
  2502.      * Should never get here.
  2503.      */
  2504.     return((MenuItem *)0);
  2505. }
  2506.  
  2507. /*
  2508.  * Unmap_Menu() unmaps a menu, if it is currently mapped.
  2509.  */
  2510. static Unmap_Menu(menu)
  2511. register Menu *menu;
  2512. {
  2513.     register int i;
  2514.  
  2515.     if(!menu || !(menu->menuFlags & menuMapped))
  2516.         return;
  2517.     if(menu->menuFlags & menuFreeze) {
  2518.         XUnmapTransparent(menu->menuWindow);
  2519.         i = 2 * menu->menuBorderWidth;
  2520.         XPixmapPut(RootWindow, 0, 0, menu->menuSavedImageX,
  2521.          menu->menuSavedImageY, menu->menuWidth + i,
  2522.          menu->menuHeight + i, menu->menuSavedImage,
  2523.          GXcopy, AllPlanes);
  2524.         XFreePixmap(menu->menuSavedImage);
  2525.         XUngrabServer();
  2526.     } else
  2527.         XUnmapWindow(menu->menuWindow);
  2528.     menu->menuFlags &= ~menuMapped;
  2529. }
  2530. #endif MODEMENU
  2531. RAZZLE!DAZZLE
  2532. fi    # End menu.c
  2533. echo '***** End of' xterm 6.6B - Part 5 of 7 '*****'
  2534. exit
  2535.